package com.yunquan.ohana.service

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import com.google.gson.Gson
import com.yunquan.ohana.base.bus.RxBus
import com.yunquan.ohana.base.bus.RxSubscriptions
import com.yunquan.ohana.db.DBFrames
import com.yunquan.ohana.db.DBPhoto
import com.yunquan.ohana.db.DBPhotoFrames
import com.yunquan.ohana.entity.EventEntity
import com.yunquan.ohana.entity.EventType
import com.yunquan.ohana.entity.FileEntity
import com.yunquan.ohana.entity.FileGroupEntity
import com.yunquan.ohana.entity.LocalFileEntity
import com.yunquan.ohana.entity.LocalPhotoFrames
import com.yunquan.ohana.entity.UploadRequestEntity
import com.yunquan.ohana.entity.UploadResponseEntity
import com.yunquan.ohana.http.BaseHttp
import com.yunquan.ohana.http.body.ProgressRequestBody
import com.yunquan.ohana.http.exception.ApiException
import com.yunquan.ohana.http.observer.BaseObserver
import com.yunquan.ohana.http.transformer.BaseResult
import com.yunquan.ohana.http.transformer.CommonTransformer
import com.yunquan.ohana.utils.L
import com.yunquan.ohana.utils.StringUtils
import com.yunquan.ohana.utils.ToastUtils
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.disposables.Disposable
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.toRequestBody
import retrofit2.Call
import java.io.File
import java.util.UUID
import java.util.concurrent.Executors
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit

class DataUploadService : Service() {

    inner class DataUploadBinder : Binder() {
        fun getService(): DataUploadService {
            return this@DataUploadService
        }
    }

    private val mBinder = DataUploadBinder()
    private var mSubscription: Disposable? = null

    private var isRevoke = false
    private val mSendFileSub = mutableMapOf<String, Call<BaseResult<FileEntity>>>()
    private val mSendBeanSub = mutableMapOf<String, Disposable>()

    private val mThreadPool = ThreadPoolExecutor(
        2,                     // 核心线程数
        4,                     // 最大线程数
        30, TimeUnit.SECONDS,   // 空闲线程存活时间
        LinkedBlockingQueue(100), // 任务队列，最多存储 10000 个等待任务
        Executors.defaultThreadFactory(), // 线程工厂
        ThreadPoolExecutor.AbortPolicy() // 拒绝策略：任务超出时抛出异常
    )

    override fun onBind(p0: Intent?): IBinder {
        return mBinder
    }

    override fun onUnbind(intent: Intent?): Boolean {
        return super.onUnbind(intent)
    }

    override fun onCreate() {
        super.onCreate()
        initRxBus()
        L.i("数据上传服务启动啦！！！")
    }

    override fun onDestroy() {
        super.onDestroy()
        mThreadPool.shutdown()
        RxSubscriptions.remove(mSubscription)
        for (e in mSendFileSub.values) {
            e.cancel()
        }
        for (e in mSendBeanSub.values) {
            e.dispose()
        }
        mSendFileSub.clear()
        mSendBeanSub.clear()
        L.i("数据上传服务死掉啦！！！")
    }

    private fun initRxBus() {
        mSubscription = RxBus.getDefault().toObservable(EventEntity::class.java)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe({ t ->
                if (t.type == EventType.SEND_TO_FRAMES) {
                    // 发送相册到相框
                    isRevoke = false
                    val data = t.data as UploadRequestEntity
                    sendToFrames(data)
                } else if (t.type == EventType.RESEND) {
                    // 重新发送
                    isRevoke = false
                    val groupId = t.data as FileGroupEntity
                    resend(groupId)
                } else if (t.type == EventType.REVOKE_SEND_POST) {
                    // 撤销发送中
                    try {
                        isRevoke = true
                        val groupId = t.data as String?
                        if (!StringUtils.isEmpty(groupId)) {
                            mSendFileSub[groupId]?.cancel()
                            mSendBeanSub[groupId]?.dispose()
                        }
                    } catch (_: Exception) {
                    }
                }
            }, { throwable ->
                L.e("RxBus 接收报错：${throwable.message}")
            })
        RxSubscriptions.add(mSubscription)
    }

    /**
     * 发送文件
     */
    private fun sendToFrames(data: UploadRequestEntity) {
        val frames = data.frames
        val photos = data.photos
        if (frames.isEmpty()) {
            ToastUtils.showShort("没有相册")
            return
        }
        val groupId = UUID.randomUUID().toString()
        // 存储关联设备
        for (e in frames) {
            val bean = LocalPhotoFrames(
                id = null,
                groupId = groupId,
                framesId = e.id,
                status = 0,
            )
            DBPhotoFrames.instance.insert(bean)
        }
        // 存储文件
        for (e in photos) {
            val bean = LocalFileEntity(
                id = null,
                serviceId = null,
                groupId = groupId,
                serviceGroupId = null,
                content = e.content,
                fileName = null,
                fileUrl = null,
                localFileId = e.id?.toString(),
                localFilePath = e.path,
                localCropId = e.cropId?.toString(),
                localCropPath = e.cropPath,
                videoImgUrl = null,
                thumbnail = e.thumbnail,
                duration = e.duration?.toInt(),
                height = e.height,
                width = e.width,
                status = 0,
                type = data.type,
                createTime = System.currentTimeMillis(),
            )
            DBPhoto.instance.insert(bean)
        }
        sendSync(groupId)
    }

    /**
     * 重发文件
     */
    private fun resend(data: FileGroupEntity) {
        for (e in data.frames) {
            val bean = LocalPhotoFrames(
                id = null,
                groupId = data.groupId,
                framesId = e.deviceId,
                status = 0,
            )
            DBPhotoFrames.instance.insert(bean)
        }
        for (e in data.photos) {
            DBPhoto.instance.insert(e)
        }
        sendSync(data.groupId!!)
    }

    /**
     * 同步发送
     */
    private fun sendSync(groupId: String) {
        mThreadPool.execute {
            try {
                DBPhotoFrames.instance.updateStatus(groupId, 0)
                val photosFrames = DBPhotoFrames.instance.selectByGroupId(groupId)
                val framesIds = photosFrames.map { it.framesId!! }.toList()
                val localFrames = DBFrames.instance.selectInDeviceIds(framesIds)
                val localPhotos = DBPhoto.instance.selectByGroupId(groupId)
                val localData = FileGroupEntity(
                    groupId = groupId,
                    serviceGroupId = null,
                    photos = localPhotos,
                    frames = localFrames,
                )
                // 发送历史记录通知
                RxBus.getDefault().post(EventEntity(EventType.UPLOAD_FILE, localData))
                if (localPhotos.first().serviceId == null) {
                    //上传文件
                    val result = uploadFile(groupId, localPhotos)
                    if (isRevoke) {
                        return@execute
                    }
                    if (!result) {
                        RxBus.getDefault().post(EventEntity(EventType.UPLOAD_FAILED, localData))
                        return@execute
                    }
                    //更新文件表
                    for (e in localPhotos) {
                        DBPhoto.instance.update(e)
                    }
                }
                if (isRevoke) {
                    return@execute
                }
                //发送到相册
                uploadToFrames(localData)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    /**
     * 同步上传文件
     */
    private fun uploadFile(groupId: String, data: List<LocalFileEntity>): Boolean {
        val fileList = mutableListOf<FileEntity>()
        val childTotal = 100f / data.size
        for (e in data) {
            try {
                val filePath = e.localCropPath ?: e.localFilePath!!
                val file = File(filePath)
//                val body = file.asRequestBody("multipart/form-data".toMediaType())
                val body = ProgressRequestBody(file) { uploaded, total ->
                    //更新上传进度
                    val uploadScale = uploaded.toFloat() / total.toFloat()
                    val childScale = childTotal * uploadScale
                    val progress = childScale + fileList.size * childTotal
                    val bean = UploadResponseEntity(groupId, progress.toInt())
                    RxBus.getDefault().post(EventEntity(EventType.UPLOAD_FILE_PROGRESS, bean))
                }
                val part = MultipartBody.Part.createFormData("file", file.name, body)
                val call = BaseHttp.api.uploadFileSync(e.type!!, part)
                mSendFileSub[groupId] = call
                val response = call.execute()
                if (response.isSuccessful) {
                    val result = response.body()
                    if (result?.code == 0) {
                        //上传完成
                        val bean = result.data!!
                        e.fileName = bean.fileName
                        e.fileUrl = bean.fileUrl
                        e.serviceId = bean.id
                        e.videoImgUrl = bean.videoImgUrl
                        e.duration = bean.lengthInTime
                        e.height = bean.height
                        e.width = bean.width
                        fileList.add(bean)
                    } else {
                        // 上传失败
                        return false
                    }
                } else {
                    // 上传失败
                    return false
                }
            } catch (e: Exception) {
                e.printStackTrace()
                return false
            } finally {
                mSendFileSub.remove(groupId)
            }
        }
        return true
    }

    /**
     * 上传信息，发送到相册
     */
    private fun uploadToFrames(data: FileGroupEntity) {
        val params = mutableMapOf<String, Any>()
        params["deviceIdList"] = data.frames.map { it.deviceId }.toList()
        params["userTrendsList"] = data.photos.map {
            val map = mutableMapOf<String, Any?>()
            map["type"] = it.type
            map["content"] = it.content
            map["fileIds"] = it.serviceId
            map
        }.toList()
        val json = Gson().toJson(params)
        val body = json.toRequestBody(BaseHttp.MEDIA_TYPE_JSON)
        BaseHttp.api.sendToAlbum(body)
            .compose(CommonTransformer())
            .subscribe(object : BaseObserver<String>() {
                override fun onSubscribe(d: Disposable) {
                    super.onSubscribe(d)
                    mSendBeanSub[data.groupId!!] = d
                }

                override fun onSuccess(result: String?) {
                    super.onSuccess(result)
                    data.serviceGroupId = result
                    for (e in data.photos) {
                        e.status = 1
                        e.serviceGroupId = result
                        DBPhoto.instance.update(e)
                    }
                    RxBus.getDefault().post(EventEntity(EventType.UPLOAD_SUCCESS, data))
                }

                override fun onError(e: ApiException) {
                    super.onError(e)
                    if (isRevoke) {
                        return
                    }
                    for (p in data.photos) {
                        p.status = 2
                        DBPhoto.instance.update(p)
                    }
                    RxBus.getDefault().post(EventEntity(EventType.UPLOAD_FAILED, data))
                }

                override fun onComplete() {
                    super.onComplete()
                    mSendBeanSub.remove(data.groupId)
                }
            })
    }
}